package com.sheng.leetcode.year2023.month08.day03;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * @author liusheng
 * @date 2023/08/03
 * <p>
 * 722. 删除注释
 * <p>
 * 给一个 C++ 程序，删除程序中的注释。这个程序source是一个数组，其中source[i]表示第 i 行源码。 这表示每行源码由 '\n' 分隔。
 * 在 C++ 中有两种注释风格，行内注释和块注释。
 * 字符串// 表示行注释，表示//和其右侧的其余字符应该被忽略。
 * 字符串* 表示一个块注释，它表示直到下一个（非重叠）出现的*之间的所有字符都应该被忽略。
 * （阅读顺序为从左到右）非重叠是指，字符串*并没有结束块注释，因为注释的结尾与开头相重叠。
 * 第一个有效注释优先于其他注释。
 * 如果字符串//出现在块注释中会被忽略。
 * 同样，如果字符串/*出现在行或块注释中也会被忽略。
 * 如果一行在删除注释之后变为空字符串，那么不要输出该行。即，答案列表中的每个字符串都是非空的。
 * 样例中没有控制字符，单引号或双引号字符。
 * 比如，source = "string s = "* Not a comment. *";"不会出现在测试样例里。
 * 此外，没有其他内容（如定义或宏）会干扰注释。
 * 我们保证每一个块注释最终都会被闭合， 所以在行或块注释之外的/*总是开始新的注释。
 * 最后，隐式换行符可以通过块注释删除。 有关详细信息，请参阅下面的示例。
 * 从源代码中删除注释后，需要以相同的格式返回源代码。
 * <p>
 * 输入: source = ["/Test program /", "int main()", "{", "  // variable declaration ", "int a, b, c;", "/ This is a test", "   multiline  ", "   comment for ", "   testing /", "a = b + c;", "}"]
 * 输出:["int main()","{ ","  ","int a, b, c;","a = b + c;","}"]
 */
public class LeetCode0722 {

    @Test
    public void test01() {
        String[] source = {"/*Test program */", "int main()", "{ ", "  // variable declaration ", "int a, b, c;", "/* This is a test", "   multiline  ", "   comment for ", "   testing */", "a = b + c;", "}"};
        System.out.println(new Solution().removeComments(source));
    }
}

class Solution {
    public List<String> removeComments(String[] source) {
        List<String> list = new ArrayList<>();
        // 用来表示当前代码是否处于注释中，初始为 false
        boolean flag = false;
        StringBuilder t = new StringBuilder();
        // 如果当前处于块注释中，那么如果当前字符和下一个字符是 '*/'，说明块注释结束，将 flag 置为 false，并且跳过这两字符，否则，继续保持块注释状态，不做任何操作
        // 如果当前不处于快注释中，那么如果当前字符和下一个字符是 '/*'，说明块注释开始，将 flag 置为 true，并且跳过这两个字符
        // 如果当前字符和下一个字符是 '//'，说明行注释开始，直接退出当前行的遍历
        // 否则说明当前为有效字符，将其加入 t 中
        // 遍历完当前行后，如果 flag 为 false，并且 t 不为空，说明当前行是有效行，加入答案数组，并且清空 t，开始遍历下一行
        for (String s : source) {
            for (int i = 0; i < s.length(); i++) {
                if (flag) {
                    if (i + 1 < s.length() && s.charAt(i) == '*' && s.charAt(i + 1) == '/') {
                        flag = false;
                        i++;
                    }
                } else {
                    if (i + 1 < s.length() && s.charAt(i) == '/' && s.charAt(i + 1) == '*') {
                        flag = true;
                        i++;
                    } else if (i + 1 < s.length() && s.charAt(i) == '/' && s.charAt(i + 1) == '/') {
                        break;
                    } else {
                        t.append(s.charAt(i));
                    }
                }
            }
            if (!flag && t.length() > 0) {
                list.add(t.toString());
                t = new StringBuilder();
            }
        }
        return list;
    }
}
